package utils.titles;

import com.google.common.base.CaseFormat;
import com.google.common.base.Joiner;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * Created by thormentor on 19-05-2014.
 */
public class Title {
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Title title = (Title) o;

        return upperCamel.equals(title.upperCamel);
    }

    @Override
    public int hashCode() {
        return upperCamel.hashCode();
    }

    public static final TitleFormatter SNAKE_CASE = new GuavaTitleFormatter(CaseFormat.LOWER_UNDERSCORE);
    public static final TitleFormatter PASCAL_CASE = new GuavaTitleFormatter(CaseFormat.UPPER_CAMEL);

    public static final TitleFormatter CAPITAL_CASE = new Capitalized();
    public static final TitleFormatter LOWER_CASE = new Lowered();

    public static final TitleFormatter LOWER_CAMEL = new GuavaTitleFormatter(CaseFormat.LOWER_CAMEL);
    public static final TitleFormatter UPPER_UNDERSCORE = new GuavaTitleFormatter(CaseFormat.UPPER_UNDERSCORE);

    private transient final String upperCamel;

    public Title(String upperCamel) {
        if (upperCamel.length() == 0)
            throw new RuntimeException();
        this.upperCamel = upperCamel;
    }

    public String toUpperCamel() {
        return upperCamel;
    }

    public static Title fromObject(Object o) {
        return fromClass(o.getClass());
    }

    public static Title fromClass(Class<?> aClass) {
        return fromPascalCase(aClass.getSimpleName());
    }

    public static Title fromPascalCase(String upperCamel) {
        return new Title(upperCamel);
    }

    public String toLowerCamel() {
        return LOWER_CAMEL.format(this);
    }

    public String toCapitalized() {
        return CAPITAL_CASE.format(this);
    }

    public static Title fromSnakeCase(String lowerUnderscore) {
        return fromPascalCase(SNAKE_CASE.toUpperCamel(lowerUnderscore));
    }

    public static Title fromLowered(String lowered) {
        return fromPascalCase(LOWER_CASE.toUpperCamel(lowered));
    }

    public static Title fromCapitalized(String capitalized) {
        return fromPascalCase(CAPITAL_CASE.toUpperCamel(capitalized));
    }

    public String toSnakeCase() {
        return SNAKE_CASE.format(this);
    }

    public Title getSingularized() {
        return fromPascalCase(Inflector.singularize(toUpperCamel()));
    }

    public Title getPluralized() {
        return fromPascalCase(Inflector.pluralize(toUpperCamel()));
    }

    public Title suffix(String suffix) {
        return fromPascalCase(upperCamel + suffix);
    }

    public Title prefix(String prefix) {
        return fromPascalCase(prefix + upperCamel);
    }

    public static Title fromLowerCamel(String lowerCamel) {
        return fromPascalCase(LOWER_CAMEL.toUpperCamel(lowerCamel));
    }

    public String toLowerCase() {
        return LOWER_CASE.format(this);
    }

    public Title cutLast() {
        ArrayList<String> strings = new ArrayList<>(Arrays.asList(toSnakeCase().split("_")));
        strings.remove(strings.size() - 1);
        return Title.fromSnakeCase(Joiner.on("_").join(strings));
    }

    @Override
    public String toString() {
        return toCapitalized();
    }

    public String toUpperUnderscore() {
        return UPPER_UNDERSCORE.format(this);
    }

    public static interface TitleFormatter {
        String toUpperCamel(String version);

        Title parse(String version);

        String format(Title title);
    }

    public static abstract class AbstractTitleFormatter implements Title.TitleFormatter{
        @Override
        public Title parse(String version) {
            return new Title(toUpperCamel(version));
        }
    }
    /**
     * Created by thormentor on 19-05-2014.
     */
    public static class GuavaTitleFormatter extends AbstractTitleFormatter {
        private CaseFormat caseFormat;

        public GuavaTitleFormatter(CaseFormat caseFormat) {
            this.caseFormat = caseFormat;
        }

        @Override
        public String toUpperCamel(String version) {
            return caseFormat.to(CaseFormat.UPPER_CAMEL, version);
        }

        @Override
        public String format(Title title) {
            return CaseFormat.UPPER_CAMEL.to(caseFormat, title.toUpperCamel());
        }
    }

    private static class Capitalized extends AbstractTitleFormatter {

        @Override
        public String toUpperCamel(String version) {
            return LOWER_CASE.toUpperCamel(version.toLowerCase());
        }

        @Override
        public String format(Title title) {
            return title.toUpperCamel().charAt(0) + LOWER_CASE.format(title).substring(1);
        }
    }

    private static class Lowered extends AbstractTitleFormatter {
        @Override
        public String toUpperCamel(String version) {
            return SNAKE_CASE.toUpperCamel(version.replace(" ", "_"));
        }

        @Override
        public String format(Title title) {
            return SNAKE_CASE.format(title).replace("_", " ");
        }
    }
}
